class Compile {
  constructor(el, vm) {
    this.$el = document.querySelector(el);
    this.$vm = vm;
    if (this.$el) {
      this.$fragment = this.node2Fragment(this.$el);
      // 对dom碎片进行编译
      this.compile(this.$fragment);
      // 把编译后的dom碎片。放回el
      this.$el.appendChild(this.$fragment);
    }
  }
  node2Fragment(el) {
    const frag = document.createDocumentFragment();
    let child;
    while ((child = el.firstChild)) {
      frag.appendChild(child);
    }
    return frag;
  }
  compile(el) {
    const childNodes = el.childNodes;
    Array.from(childNodes).forEach((node) => {
      if (this.isElement(node)) {
        // 对vdom编译
        const nodeAttrs = node.attributes;
        Array.from(nodeAttrs).forEach((attr) => {
          const attrName = attr.name;
          const exp = attr.value;
          if (this.isDirective(attrName)) {
            // 编译指令
            const dir = attrName.substring(2);
            this[dir] && this[dir](node, this.$vm, exp);
          }
          if (this.isEvent(attrName)) {
            const dir = attrName.substring(1);
            this.eventHandler(node, this.$vm, exp, dir);
          }
        });
      } else if (this.isText(node)) {
        this.compileText(node);
      }
      // 如果有嵌套dom，就递归
      if (node.childNodes && node.childNodes.length !== 0) {
        this.compile(node);
      }
    });
  }
  compileText(node) {
    this.update(node, this.$vm, RegExp.$1, "text");
  }
  update(node, vm, exp, dir) {
    const updateFn = this[dir + "Updater"];
    updateFn && updateFn(node, $operationObj.getObjKey(vm, exp));

    new Watcher(vm, exp, function (value) {
      updateFn && updateFn(node, value);
    });
  }
  text(node, vm, exp) {
    this.update(node, vm, exp, "text");
  }
  model(node, vm, exp) {
    this.update(node, vm, exp, "model");
    node.addEventListener(
      "input",
      (e) => {
        vm[exp] = e.target.value;
      },
      false
    );
  }
  html(node, vm, exp) {
    this.update(node, vm, exp, "html");
  }
  for(node, vm, exp) {
    exp = exp.split(" of ")[1];
    this.update(node, vm, exp, "for");
  }
  textUpdater(node, exp) {
    node.textContent = exp;
  }
  htmlUpdater(node, exp) {
    node.innerHTML = exp;
  }
  forUpdater(node, exp) {
    // const frag = document.createDocumentFragment();
    // for (let i of exp) {
    //   node.textContent = i;
    //   console.log( node.textContent)
    //   frag.appendChild(node);
    // }
    // console.log(frag)
    // const dom = document.createElement('div');
    // dom.innerHTML = '1111';
    // node = dom
    // console.log(node)
    // // node = frag;
  }
  eventHandler(node, vm, exp, dir) {
    let fn = vm.$options.methods && vm.$options.methods[exp];
    if (dir && fn) {
      node.addEventListener(dir, fn.bind(vm), false);
    }
  }
  isElement(node) {
    // 1 就是vdom
    return node.nodeType === 1;
  }
  isEvent(attr) {
    return attr.indexOf("@") === 0;
  }
  isDirective(attr) {
    return attr.indexOf("m-") === 0;
  }
  isText(node) {
    return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent);
  }
}
